package com.pingan.pastry.rpc.support;

import com.google.gson.Gson;
import com.pingan.pastry.common.REQUEST_TYPE;
import com.pingan.pastry.common.annotation.Fn;
import com.pingan.pastry.common.annotation.Param;
import com.pingan.pastry.common.exception.InvokeException;
import com.pingan.pastry.rpc.SPI;
import com.pingan.pastry.rpc.util.HttpClientUtil;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.Map;

public class MethodHandler {
    private String url;
    private Parameter[] parameters;
    private Class<?> returnType;
    private REQUEST_TYPE requestType;

    private Gson gson = new Gson();


    public MethodHandler(Method method, String host) {
        url = obtainUrl(method, host);
        parameters = method.getParameters();
        returnType = method.getReturnType();
        requestType = getRequestType(method);
    }

    private REQUEST_TYPE getRequestType(Method method) {
        if (requestType == null) {
            Fn annotation = method.getAnnotation(Fn.class);
            if (annotation != null) {
                requestType = annotation.requestType();
            }
        }
        return requestType;
    }

    private String bindGetParamToUrl(Object[] args, String url) {
        StringBuffer urlBuffer = new StringBuffer();
        urlBuffer.append(url);
        if (parameters != null && parameters.length > 0) {
            urlBuffer.append("?");
            for (int i = 0; i < parameters.length; i++) {
                Parameter parameter = parameters[i];
                Param annotation = parameter.getAnnotation(Param.class);
                String paramName = annotation.value();
                urlBuffer.append(paramName);
                urlBuffer.append("=");
                urlBuffer.append(args[i]);
                if (i < parameters.length - 1) {
                    urlBuffer.append("&");
                }
            }
        }
        return urlBuffer.toString();
    }

    private String bindParams(Object[] args) {
        Map<String,Object> paramMap = new HashMap<>();
        if (parameters != null && parameters.length > 0) {
            for (int i = 0; i < parameters.length; i++) {
                Parameter parameter = parameters[i];
                Param annotation = parameter.getAnnotation(Param.class);
                if (annotation != null) {
                    String paramName = annotation.value();
                    paramMap.put(paramName, args[i]);
                }
            }
        }
        return gson.toJson(paramMap);
    }

    private String obtainUrl(Method method, String host) {
        Class<?> declaringClass = method.getDeclaringClass();
        SPI spi = declaringClass.getDeclaredAnnotation(SPI.class);
        Fn fn = method.getAnnotation(Fn.class);
        String url = null;
        if (spi != null && fn != null) {
            url = host + spi.value() + fn.value();
        }
        return url;
    }


    public Object handle(Object[] args, int connectionTimeout, int socketTimeout) {
        String result = null;
        try {
            switch (requestType) {
                case GET:
                    String urlResource = bindGetParamToUrl(args, url);
                    result = HttpClientUtil.processGet(urlResource, connectionTimeout, socketTimeout);
                    break;
                case POST:
                    String param = bindParams(args);
                    result = HttpClientUtil.processPost(url, param, "text/plain; charset=UTF-8", connectionTimeout, socketTimeout);
            }
        } catch (Exception e) {
            throw new InvokeException("url: +" + url + " 远程调用失败:" + e.getMessage());
        }
        return gson.fromJson(result, returnType);
    }

}
